﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides a rotation matrix for three dimensional vectors.
    /// </summary>
    [Serializable]
    public class RotationMartix3D
    {
        /// <summary>
        /// The rotation angle for the x axis.
        /// </summary>
        private double rotationAngleX;

        /// <summary>
        /// The rotation angle for the y axis.
        /// </summary>
        private double rotationAngleY;

        /// <summary>
        /// The rotation angle for the z axis.
        /// </summary>
        private double rotationAngleZ;

        /// <summary>
        /// Initializes a new instance of the <see cref="RotationMartix3D"/> class.
        /// </summary>
        /// <param name="transformAngle">The rotation angle for all axis in radians.</param>
        public RotationMartix3D(double transformAngle)
        {
            this.rotationAngleX = transformAngle;
            this.rotationAngleY = transformAngle;
            this.rotationAngleZ = transformAngle;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RotationMartix3D"/> class.
        /// </summary>
        /// <param name="transformAngleX">The rotation angle for the x axis in radians.</param>
        /// <param name="transformAngleY">The rotation angle for the y axis in radians.</param>
        /// <param name="transformAngleZ">The rotation angle for the z axis in radians.</param>
        public RotationMartix3D(double transformAngleX, double transformAngleY, double transformAngleZ)
        {
            this.rotationAngleX = transformAngleX;
            this.rotationAngleY = transformAngleY;
            this.rotationAngleZ = transformAngleZ;
        }

        /// <summary>
        /// Gets or sets the rotation angle for the x axis.
        /// </summary>
        /// <value>The rotation angle for the x axis.</value>
        public double RotationAngleX
        {
            get { return rotationAngleX; }
            set { rotationAngleX = value; }
        }

        /// <summary>
        /// Gets or sets the rotation angle for the y axis.
        /// </summary>
        /// <value>The rotation angle for the y axis.</value>
        public double RotationAngleY
        {
            get { return rotationAngleY; }
            set { rotationAngleY = value; }
        }

        /// <summary>
        /// Gets or sets the rotation angle for the z axis.
        /// </summary>
        /// <value>The rotation angle for the z axis.</value>
        public double RotationAngleZ
        {
            get { return rotationAngleZ; }
            set { rotationAngleZ = value; }
        }

        /// <summary>
        /// Gets the rotation matrix for the x axis.
        /// </summary>
        /// <returns>The rotation matrix for the x axis.</returns>
        public Matrix GetRotationMatrixAxisX()
        {
            double[,] matrixData = new double[3,3];

            matrixData[0, 0] = 1;
            matrixData[0, 1] = 0;
            matrixData[0, 2] = 0;

            matrixData[1, 0] = 0;
            matrixData[1, 1] = Math.Cos(this.rotationAngleX);
            matrixData[1, 2] = -Math.Sin(this.rotationAngleX);

            matrixData[2, 0] = 0;
            matrixData[2, 1] = Math.Sin(this.rotationAngleX);
            matrixData[2, 2] = Math.Cos(this.rotationAngleX);

            return new Matrix(matrixData);
        }

        /// <summary>
        /// Gets the rotation matrix for the y axis.
        /// </summary>
        /// <returns>The rotation matrix for the y axis.</returns>
        public Matrix GetRotationMatrixAxisY()
        {
            double[,] matrixData = new double[3,3];

            matrixData[0, 0] = Math.Cos(this.rotationAngleY);
            matrixData[0, 1] = 0;
            matrixData[0, 2] = Math.Sin(this.rotationAngleY);

            matrixData[1, 0] = 0;
            matrixData[1, 1] = 1;
            matrixData[1, 2] = 0;

            matrixData[2, 0] = -Math.Sin(this.rotationAngleY);
            matrixData[2, 1] = 0;
            matrixData[2, 2] = Math.Cos(this.rotationAngleY);

            return new Matrix(matrixData);
        }

        /// <summary>
        /// Gets the rotation matrix for the z axis.
        /// </summary>
        /// <returns>The rotation matrix for the z axis.</returns>
        public Matrix GetRotationMatrixAxisZ()
        {
            double[,] matrixData = new double[3,3];

            matrixData[0, 0] = Math.Cos(this.rotationAngleZ);
            matrixData[0, 1] = -Math.Sin(this.rotationAngleZ);
            matrixData[0, 2] = 0;

            matrixData[1, 0] = Math.Sin(this.rotationAngleZ);
            matrixData[1, 1] = Math.Cos(this.rotationAngleZ);
            matrixData[1, 2] = 0;

            matrixData[2, 0] = 0;
            matrixData[2, 1] = 0;
            matrixData[2, 2] = 1;

            return new Matrix(matrixData);
        }

        /// <summary>
        /// Gets the rotation matrix for all three axis.
        /// </summary>
        /// <returns>The rotation matrix for all three axis.</returns>
        public Matrix GetRotationMatrix()
        {
            return this.GetRotationMatrixAxisX() * this.GetRotationMatrixAxisY()
                   * this.GetRotationMatrixAxisZ();
        }
    }
}